package com.example.springbootaccesslimit.interceptor;

import com.alibaba.fastjson.JSON;
import com.example.springbootaccesslimit.anno.AccessLimit;
import com.example.springbootaccesslimit.entry.Result;
import com.example.springbootaccesslimit.enums.CodeMsg;
import com.example.springbootaccesslimit.utils.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;

/**
 * 防刷拦截器
 *
 * @author lxiaol
 * @date 2022年02月09日 22:32
 */

@Component
public class AccessLimitInterceptor implements HandlerInterceptor {

    @Autowired
    private RedisUtil redisUtil;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        //方法请求拦截
        if (handler instanceof HandlerMethod) {

            HandlerMethod hm = (HandlerMethod) handler;

            //获取方法中的AccessLimit注解
            AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);
            if (accessLimit == null) {
                return true;
            }
            int seconds = accessLimit.seconds();
            int maxCount = accessLimit.maxCount();
            String uri = request.getRequestURI();
            //这里简单用用户名代替，建议用通过校验的token
            String token = "username";
            String key = token + uri;
            //从redis中获取用户访问的次数
            Object count = redisUtil.get(key);
            if (count == null) {
                //第一次访问
                redisUtil.set(key, 1, (long) seconds, TimeUnit.SECONDS);
            } else if (Integer.parseInt(count.toString()) < maxCount) {
                //加1
                redisUtil.incr(key);
            } else {
                //超出访问次数
                render(response);
                return false;
            }
        }

        return true;
    }

    /**
     * 超出访问次数 给出提示
     * @param response
     * @throws Exception
     */
    private void render(HttpServletResponse response) throws Exception {
        response.setContentType("application/json;charset=UTF-8");
        OutputStream out = response.getOutputStream();
        String str = JSON.toJSONString(Result.codeMsg(CodeMsg.ACCESS_LIMIT_REACHED));
        out.write(str.getBytes(StandardCharsets.UTF_8));
        out.flush();
        out.close();
    }

}
